package com.etc.reflectdemo;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据访问通用类
 */
public final class DBUtil {

    private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
    private static final String URL = "jdbc:mysql://localhost:3306/tushumanager?serverTimezone=Asia/Shanghai";
    private static final String PASSWORD = "root";
    private static final String USER = "root";

    private DBUtil() {
        // TODO Auto-generated constructor stub
    }

    /**
     * 获取连接对象Connection
     *
     * @return java.sql.Connection
     */
    public static Connection getConn() {
        Connection conn = null;
        try {
            Class.forName(DRIVER);
            // 2创建connection
            // 得到连接对象
            conn = DriverManager.getConnection(URL, USER, PASSWORD);
        } catch (ClassNotFoundException | SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return conn;
    }

    /**
     * 通用的增加，删除，修改的代码
     *
     * @param sql    要执行的sql语句
     * @param params 占位符的值，可以用数组来传递或者直接赋值
     * @return int 受影响的行
     */
    public static int exUpdate(String sql, Object... params) {

        Connection conn = null;
        PreparedStatement pstmt = null;
        int result = 0;
        try {
            conn = getConn();
            // 3创建一个PreparedStatement =>增加 删除 修改 完全一致，除了sql语句不同
            pstmt = conn.prepareStatement(sql);
            // 调用设置参数的方法
            setPstmt(pstmt, params);
            // 5 执行sql
            result = pstmt.executeUpdate();

        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            // 释放资源
            closeAll(pstmt, conn, null);
        }

        return result;

    }

    /**
     * 设置参数,补齐占位符
     *
     * @param pstmt  PreparedStatement
     * @param params 占位符的数据值列表(数组)
     */
    private static void setPstmt(PreparedStatement pstmt, Object... params) {
        // 补齐占位符
        if (params != null) {
            for (int i = 0; i < params.length; i++) {
                try {
                    pstmt.setObject(i + 1, params[i]);
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        System.out.println(pstmt);
    }

    /**
     * 释放资源你的方法
     *
     * @param pstmt PreparedStatement 对象
     * @param conn  Connection 连接对象
     * @param rs    ResultSet 结果集对象
     */
    public static void closeAll(PreparedStatement pstmt, Connection conn, ResultSet rs) {
        // 6 释放资源
        try {
            if (pstmt != null) {
                pstmt.close();
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * @param sql
     * @param cls
     * @param params
     * @return
     */
    public static List exQuery(String sql, Class cls, Object... params) {

        List list = new ArrayList();
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet result = null;
        try {
            conn = getConn();
            // 3创建一个PreparedStatement =>增加 删除 修改 完全一致，除了sql语句不同
            pstmt = conn.prepareStatement(sql);
            // 调用设置参数的方法
            setPstmt(pstmt, params);
            // 5 执行sql
            result = pstmt.executeQuery();
            while (result.next()) {
                list.add(convert(result, cls));
            }

        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            // 释放资源
            closeAll(pstmt, conn, result);
        }

        return list;
    }

    /**
     * 将数据库中结果(ResultSet)
     * 中的每一行读取出来，将数据赋值给Class类型指向的那个对象，并return
     * <p>
     * 数据库表中的记录行->java对象
     *
     * @param rs  结果集
     * @param cls Class对象
     * @return 对象
     */
    public static Object convert(ResultSet rs, Class cls) {
        Object obj = null;


        try {
            //1 通过Class对象创建对应那个类型的实例
            obj = cls.newInstance(); //可以用，注意9之后要用我们的Constructor的方法
            //读取的数据库中一行结果集=》转换为对应的 实体类的对象 => 赋值
            //ORM
            //以： -》实体类为准
            Field[] declaredFields = cls.getDeclaredFields();
            //得到查询的字段的信息[类]=>
            for (int i = 0; i < declaredFields.length; i++) {

                //得到结果集中的那个对象的值
                Object value = rs.getObject(i + 1);

                //这里就是反射的应用
                declaredFields[i].setAccessible(true);
                declaredFields[i].set(obj, value);

            }


        } catch (Exception e) {
            e.printStackTrace();
        }


        return obj;

    }

}
